<template>
  <view @click="showCity = !props.disabled?!showCity:false">
    <!-- #ifdef APP-NVUE -->
    <view :eventPenetrationEnabled="true">
      <slot></slot>
    </view>
    <!-- #endif -->
    <!-- #ifndef APP-NVUE -->
    <slot></slot>
    <!-- #endif -->
    <tm-drawer :zIndex="props.zIndex" :inContent="props.inContent" :disabbleScroll="true" :round="props.round" ref="drawer" :height="dHeight"
      :closeable="true" :overlayClick="aniover" @open="drawerOpen" @cancel="cancel" @ok="confirm" :show="showCity"
      @close="closeDrawer"
      title="请选择" ok-text="确认">
      <tm-picker-view v-if="showCity" :dataKey="props.mapKey || props.dataKey" :map-key="props.mapKey || props.dataKey" :height="dHeight - 230" @end="aniover = true"
        @start="aniover = false" :value="_colIndex" @update:modelValue="_colIndex = $event"
        @update:model-str="_colStr = $event" :model-str="_colStr" :default-value="_colIndex"
        :beforeChange="props.beforeChange" :immediateChange="props.immediateChange" :columns="_data">
      </tm-picker-view>
      <tm-button label="确认选择" block :margin="[32, 12]" :color="props.color" :linear="props.linear"
        :linear-deep="props.linearDeep" @click="confirm" :round="props.btnRound">
      </tm-button>
      <view :style="{ height: sysinfo.bottom + 'px' }"></view>
    </tm-drawer>
  </view>
</template>
<script lang="ts" setup>
/**
 * 级联选择（弹层）
 * @description 这是弹出式级联
 */
import {
  PropType,
  Ref,
  ref,
  watchEffect,
  onMounted,
  getCurrentInstance,
  computed,
  toRaw,
  inject,
  nextTick,
  watch,
} from "vue";
import { custom_props } from "../../tool/lib/minxs";
import tmDrawer from "../tm-drawer/tm-drawer.vue";
import { columnsItem } from "../tm-picker-view/interface";
import tmPickerView from "../tm-picker-view/tm-picker-view.vue";
import TmSheet from "../tm-sheet/tm-sheet.vue";
import tmText from "../tm-text/tm-text.vue";
import tmButton from "../tm-button/tm-button.vue";
const drawer = ref<InstanceType<typeof tmDrawer> | null>(null);
const proxy = getCurrentInstance()?.proxy ?? null;

/**
 * 事件说明：
 * v-model:show 双向绑定显示和隐藏选择器
 * v-model 双向绑定以selectedModel为模式的值。一般用来给数据库后台用的。
 * v-model:model-str 单向输出地区名称，
 * 一般用来绑定在Input组件或者其它组件上用来展示当前选择的地址名称，
 * 但我们服务器可能有的是id或者index，所以你可以v-model绑定数据，用此v-model:model-str来显示数据。
 * confirm 点击了确认按钮时触发，返回当前选择数据。
 * cancel 取消或者点击遮罩关闭了选择器都将触发。
 */
const emits = defineEmits([
  "update:show",
  "update:modelValue",
  "update:modelStr",
  "confirm",
  "cancel",
  "close",
  "open",
]);
const props = defineProps({
  ...custom_props,

  //可v-model,每一列选中的索引值
  modelValue: {
    type: Array as PropType<Array<number | string>>,
    default: () => [],
  },
  /**
   * 注意：这里是单向输出显示的value值，而不是modelValue的index索引值。
   * 这里主要是为了方便表单上页面的显示。如果真要保存到数据库，你应该保存modelValue的值。
   */
  modelStr: {
    type: [String],
    default: "",
  },
  //默认选中的索引值。
  defaultValue: {
    type: Array as PropType<Array<number | string>>,
    default: () => [],
  },
  //赋值和选值方式
  //name:名称模式赋值和选择
  //id:id模式赋值和选择
  //index:索引模式赋值和选择
  selectedModel: {
    type: String,
    default: "index",
  },
  //数据。
  columns: {
    type: Array as PropType<Array<columnsItem>>,
    default: () => [],
    required: true,
  },
  //当columns项目中的data数据为对象时的key取值字段。
  dataKey: {
    type: String,
    default: "text",
  },
  //当columns项目中的data数据为对象时的key取值字段。兼容上方dataKey,因为微信dataKey与本字段重名，无法设置。
  mapKey: {
    type: String,
    default: "text",
  },
  //当前改变index项时，改变时执行的函数。如果返回false，将会阻止本次改变,可以是Promise
  //提供了即将改变的数据和将要改变到目标的数据
  //结构 为 from:{itemindex,levelIndex,data},to:{itemindex,levelIndex,data}。
  beforeChange: {
    type: [Boolean, Function],
    default: () => false,
  },
  //v-model:show来双向绑定显示和隐藏选择器。
  show: {
    type: [Boolean],
    default: false,
  },
  color: {
    type: String,
    default: "primary",
  },
  linear: {
    type: String,
    default: "",
  },
  linearDeep: {
    type: String,
    default: "light",
  },
  btnRound: {
    type: Number,
    default: 3,
  },
  round: {
    type: Number,
    default: 12,
  },
  height: {
    type: Number,
    default: 700,
  },
  immediateChange: {
    type: Boolean,
    default: false,
  },
  /** 是否嵌入弹层，开启后将在它的父组件内执行弹层。 */
  inContent: {
    type: Boolean,
    default: false,
  },
  /**禁用时，通过插槽点击时，不会触发显示本组件，适合表单 */
  disabled:{
    type:Boolean,
    default:false
  },
  zIndex: {
    type: [Number, String],
    default: 999,
  },
});
const showCity = ref(true);
const _colIndex: Ref<Array<number>> = ref([]);
const _data = computed(() => props.columns);
const _colStr = ref(props.modelStr);
const aniover = ref(true);
const sysinfo = inject(
  "tmuiSysInfo",
  computed(() => {
    return {
      bottom: 0,
      height: 750,
      width: uni.upx2px(750),
      top: 0,
      isCustomHeader: false,
      sysinfo: null,
    };
  })
);
let tmid = NaN;
watchEffect(() => {
  showCity.value = props.show;
});

watch(
  [() => props.columns, () => props.modelValue],
  () => {
    clearTimeout(tmid);
    tmid = setTimeout(function () {
      getIndexBymodel(_data.value, props.selectedModel, 0, props.modelValue);
      defaultModerStrGet();
    }, 500);
  },
  { deep: true }
);

function closeDrawer(e: boolean) {
  showCity.value = e;
  emits("update:show", showCity.value);
  getIndexBymodel(_data.value, props.selectedModel, 0, props.modelValue);
  emits("close");
}

//弹层打开时触发。
function drawerOpen() {
  emits("open");
}
onMounted(() => {
  // getIndexBymodel(_data.value, props.selectedModel, 0, props.defaultValue)
  if (props.defaultValue.length > 0) {
    getIndexBymodel(_data.value, props.selectedModel, 0, props.defaultValue);
    defaultModerStrGet();
  }
});
//点击确认了地区。
function confirm() {
  // if (!aniover.value) return
  if (_colIndex.value.length == 0) {
    getIndexBymodelByEmptyOnConfirm(
      _data.value,
      props.selectedModel,
      0,
      props.defaultValue
    );
  }
  setVal();
  nextTick(() => {
    emits("confirm", toRaw(_colIndex.value));
    drawer.value?.close();
  });
}
function cancel() {
  if (!aniover.value) return;
  emits("cancel");
}
function setVal() {
  let val = [];
  if (props.selectedModel == "name") {
    val = _colStr.value.split("/") ?? [];
  } else if (props.selectedModel == "id") {
    val = getRouterId(_data.value, 0);
  } else {
    val = [..._colIndex.value];
  }
  emits("update:modelValue", val);
  emits("update:modelStr", _colStr.value);
}
function defaultModerStrGet() {
  clearTimeout(tmid);
  tmid = setTimeout(function () {
    if (!_colStr.value && _colIndex.value.length > 0) {
      let text = getRouterText(_data.value, 0);
      let str = text.join("/");
      emits("update:modelStr", str);
    }
    if (_colIndex.value.length == 0) {
      emits("update:modelStr", "");
    }
  }, 100);
}
//模拟模型来返回index值
function getIndexBymodel(
  vdata: Array<columnsItem> = [],
  model = "name",
  parentIndex: number = 0,
  value: Array<number | string> = []
): Array<number> {
  if (value.length == 0) {
    _colIndex.value = [];
    return [];
  }
  let p_colIndex = [..._colIndex.value];
  _colIndex.value = [];
  if (model == "name") {
    let item = vdata.filter((el) => value[parentIndex] == el["text"]);
    if (item.length == 0) {
      //    如果不存在,不再默认选中第一个,2022年10月14日修改
      // item = vdata[0];
      // if (item) {
      //     value[parentIndex] = item['text'];
      //     p_colIndex[parentIndex] = 0
      //     if (item['children']) {
      //         getIndexBymodel(item['children'], model, parentIndex + 1, value);
      //     }
      // }
    } else {
      item = item[0];
      if (item) {
        p_colIndex[parentIndex] = vdata.findIndex((el) => el["text"] == item["text"]);
        if (item["children"]) {
          getIndexBymodel(item["children"], model, parentIndex + 1, value);
        }
      }
    }
  } else if (model == "id") {
    let item = vdata.filter((el) => value[parentIndex] == el["id"]);
    if (item.length == 0) {
      //    如果不存在,不再默认选中第一个,2022年10月14日修改
      // item = vdata[0];
      // if (item) {
      //     value[parentIndex] = item['id'];
      //     p_colIndex[parentIndex] = 0
      //     if (item['children']) {
      //         getIndexBymodel(item['children'], model, parentIndex + 1, value);
      //     }
      // }
    } else {
      item = item[0];
      if (item) {
        p_colIndex[parentIndex] = vdata.findIndex((el) => el["id"] == item["id"]);
        if (item["children"]) {
          getIndexBymodel(item["children"], model, parentIndex + 1, value);
        }
      }
    }
  } else {
    p_colIndex = [...value];
  }
  _colIndex.value = [...p_colIndex];
  return _colIndex.value;
}
// 和上方一样的功能,区别是,当什么都不选的时候,点了确认,就要默认选中第一行数据.
function getIndexBymodelByEmptyOnConfirm(
  vdata: Array<columnsItem> = [],
  model = "name",
  parentIndex: number = 0,
  value: Array<number | string> = []
): Array<number> {
  let p_colIndex = [..._colIndex.value];
  _colIndex.value = [];
  if (model == "name") {
    let item = vdata.filter((el) => value[parentIndex] == el["text"]);
    if (item.length == 0) {
      //    如果不存在,不再默认选中第一个,2022年10月14日修改
      item = vdata[0];
      if (item) {
        value[parentIndex] = item["text"];
        p_colIndex[parentIndex] = 0;
        if (item["children"]) {
          getIndexBymodel(item["children"], model, parentIndex + 1, value);
        }
      }
    } else {
      item = item[0];
      if (item) {
        p_colIndex[parentIndex] = vdata.findIndex((el) => el["text"] == item["text"]);
        if (item["children"]) {
          getIndexBymodel(item["children"], model, parentIndex + 1, value);
        }
      }
    }
  } else if (model == "id") {
    let item = vdata.filter((el) => value[parentIndex] == el["id"]);
    if (item.length == 0) {
      //    如果不存在,不再默认选中第一个,2022年10月14日修改
      item = vdata[0];
      if (item) {
        value[parentIndex] = item["id"];
        p_colIndex[parentIndex] = 0;
        if (item["children"]) {
          getIndexBymodel(item["children"], model, parentIndex + 1, value);
        }
      }
    } else {
      item = item[0];
      if (item) {
        p_colIndex[parentIndex] = vdata.findIndex((el) => el["id"] == item["id"]);
        if (item["children"]) {
          getIndexBymodel(item["children"], model, parentIndex + 1, value);
        }
      }
    }
  } else {
    p_colIndex = [...value];
  }
  _colIndex.value = [...p_colIndex];
  return _colIndex.value;
}
//返回 一个节点从父到子的路径id组。
function getRouterId(list = [], parentIndex = 0): Array<string | number> {
  let p: Array<string | number> = [];
  for (let i = 0; i < list.length; i++) {
    if (i == _colIndex.value[parentIndex]) {
      p.push(list[i]["id"]);
      if (typeof _colIndex.value[parentIndex] != "undefined") {
        let c = getRouterId(list[i]["children"], parentIndex + 1);
        p = [...p, ...c];
      }
      break;
    }
  }
  return p;
}
//返回 一个节点从父到子的路径text组。
function getRouterText(
  list: Array<childrenData> = [],
  parentIndex = 0
): Array<string | number> {
  let p: Array<string | number> = [];
  for (let i = 0; i < list.length; i++) {
    if (i == _colIndex.value[parentIndex]) {
      p.push(list[i]["text"]);
      if (typeof _colIndex.value[parentIndex] != "undefined") {
        let c = getRouterText(list[i]["children"], parentIndex + 1);
        p = [...p, ...c];
      }
      break;
    }
  }
  return p;
}
const dHeight = computed(() => {
  return props.height + sysinfo.value.bottom + 80;
});
</script>
